<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
		<title>vue2和vue3的响应式原理</title>
	</head>
	<body>

		一、vue2.x的响应式：
		-- 对象类型：通过Object.defineProperty()对属性的读取(getter)、修改(setter)进行拦截（数据劫持）。
		-- 数组类型：通过重写更新数组的一系列（push、pop、shift、unshift、splice、sort、reverse）方法来实现拦截。（对数组的变更方法进行了包裹）。
		-- Object.defineProperty只可以getter（读取）和setter（修改）方法只可以监听对象的读取和修改
		1.存在问题：(由于 JavaScript 的限制，vue不能完全检测数组和对象的全部变化)
        -- 新增属性、删除属性, 界面不会更新。解决：this.$set、this.$delete
		-- 直接通过下标修改数组、修改数组的长度时, 界面不会自动更新。解决：this.$set、重写更新数组的一系列方法

       2、总结：
	   Vue的双向数据绑定是由数据劫持结合发布者-订阅者模式实现的。
	   数据劫持：是通过 Object.defineProperty() 来劫持对象数据的setter和getter操作；
	   发布者-订阅者模式: 在数据变动时，发布者发布消息给订阅者，触发相应监听回调。
	   当一个普通的JavaScript对象传给Vue实例，来作为他的data选项时，Vue会遍历他的每个属性，使用Object.defineProperty重新定义所有属性，监听他们的getter和setter 方法，当页面取到对应属性时，会进行依赖收集（收集当前组件的watcher），如果属性发生变化会通知相关依赖进行更新操作。
	   (1).存在问题：(由于 JavaScript 的限制，vue不能完全检测数组和对象的全部变化)
	   	-- 新增属性、删除属性, 界面不会更新。解决：this.$set、this.$delete
	   	-- 直接通过下标修改数组、通过下标添加数组、delete方法删除数组、修改数组的长度时, 界面不会自动更新。解决：this.$set、重写更新数组的一系列方法:push/pop/shift/unshift/splice/sort/reverse
		
		
		二、Vue3.0的响应式
		  - 通过Proxy（代理）:  拦截对象中任意属性的变化, 包括：属性值的读写、属性的添加、属性的删除等。
		  - 通过Reflect（反射）:  对源对象的属性进行操作。
		  - MDN文档中描述的Proxy与Reflect：
		    - Proxy：https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
		    - Reflect：https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
			  new Proxy(data, {
				// 拦截读取属性值
				  get (target, prop) {
					return Reflect.get(target, prop)
				  },
				  // 拦截设置（修改）属性值或添加新属性
				  set (target, prop, value) {
					return Reflect.set(target, prop, value)
				  },
				  // 拦截删除属性
				  deleteProperty (target, prop) {
					return Reflect.deleteProperty(target, prop)
				  }
			  })
			  proxy.name = 'tom'   
			 
	</body>
	<script type="text/javascript">


	</script>
</html>
